/*
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is
 *
 * java-concurrency-presentation:
 * concurrency presentation tutorial.
 *
 * The Initial Developer of the Original Code is
 * Marco Antonio Villalobos, Jr.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): None.
 *
 * ***** END LICENSE BLOCK *****
 */

package presentation.concurrency.indexer;

import java.io.*;

/**
 * A delegating document indexer.
 *
 * Delegates indexing to the Index class, but provides a consistent means to perform file parsing.
 */
public abstract class Indexer {

    /**
     * Provides a means for a developer to demonstrate a thread safe, or non-thread safe indexer.
     *
     * @param files The files to index.
     * @return A completed index.
     */
    public abstract Index execute(final File[] files);

    /**
     * Reads a file, parses it for words, and for each word,
     * will delegate to the given index and add the word to the index.
     *
     * This method is re-entrant and thread safe, however,
     * the Index will be thread safe, or thread unsafe, depending
     * on the motives and intent of the implementer.
     * 
     * @param index The index to add the word to.
     * @param file The file that will be indexed.
     */
    public final void index(Index index, File file) {
        Reader r;
        r = null;
        try {
            r = new BufferedReader(new FileReader(file));
            StreamTokenizer tokenizer = new StreamTokenizer(r);
            tokenizer.lowerCaseMode(true);

            while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
                String word;
                int line;

                word = null;
                line = -1;
                switch (tokenizer.ttype) {
                    case StreamTokenizer.TT_EOL:
                    case StreamTokenizer.TT_NUMBER: {
                        //do nothing
                        break;
                    }
                    case StreamTokenizer.TT_WORD: {
                        word = tokenizer.sval;
                        line = tokenizer.lineno();
                        break;
                    }
                    default:
                        word = String.valueOf((char) tokenizer.ttype);
                        line = tokenizer.lineno();
                }
                if (line != -1) {
                    int length = word.length();
                    char last = word.charAt(length - 1);
                    boolean endsWithAlpha = ('A' <= last && last <= 'Z') || ('a' <= last && last <= 'z');
                    if (endsWithAlpha) {
                        index.add(word, file.getPath(), line);
                    } else if (length > 1) {
                        index.add(word.substring(0, length - 1), file.getPath(), line);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (r != null) {
                try {
                    r.close();
                } catch (IOException e) {
                    //empty
                }
            }
        }
    }
}
